package com.arcsoft.commonbase.widgets

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import java.util.*

class PictureVerification(
		/**
		 * 验证码的长度
		 */
		private val codeLength: Int = DEFAULT_CODE_LENGTH,
		/**
		 * 字符大小
		 */
		private val fontSize: Float = DEFAULT_FONT_SIZE,
		/**
		 * 干扰线数量
		 */
		val lineNumber: Int = DEFAULT_LINE_NUMBER,
		/**
		 * 第一个字符的左边距
		 */
		private val baseFirstPaddingLeft: Int = FIRST_BASE_PADDING_LEFT,
		private val basePaddingLeft: Int = BASE_PADDING_LEFT,
		private val rangePaddingLeft: Int = RANGE_PADDING_LEFT,
		private val basePaddingTop: Int = BASE_PADDING_TOP,
		private val rangePaddingTop: Int = RANGE_PADDING_TOP,
		private val baseTextSkewX: Float = BASE_TEXT_SKEW_X,
		private val rangeTextSkewX: Float = RANGE_TEXT_SKEW_X,
		private val width: Int = DEFAULT_WIDTH,
		private val height: Int = DEFAULT_HEIGHT,
		val backgroundColor: Int = DEFAULT_COLOR,
		private val random: Random = Random()) {

	companion object {
		private const val TAG: String = "PictureVerification"

		private const val DEFAULT_CODE_LENGTH = 4 //验证码的长度  这里是4位
		private const val DEFAULT_FONT_SIZE = 55f //字体大小
		private const val DEFAULT_LINE_NUMBER = 3 //多少条干扰线
		private const val FIRST_BASE_PADDING_LEFT = 15 //第一个字符的基础左边距
		private const val BASE_PADDING_LEFT = 35 //基础左边距
		private const val RANGE_PADDING_LEFT = 15 //左边距范围值
		private const val BASE_PADDING_TOP = 70 //上边距
		private const val RANGE_PADDING_TOP = 15 //上边距范围值
		private const val BASE_TEXT_SKEW_X = 0.25f // 字体倾斜基准值
		private const val RANGE_TEXT_SKEW_X = 0.5f // 字体倾斜随机值
		private const val DEFAULT_WIDTH = 200 //默认宽度.图片的总宽
		private const val DEFAULT_HEIGHT = 100 //默认高度.图片的总高

		/**
		 * 默认背景颜色值。kt的16进制数跟java的不一样，不能直接作为颜色值使用
		 */
		private const val DEFAULT_COLOR = (0xFFEEEEEEL - Int.MAX_VALUE - 1 + Int.MIN_VALUE).toInt()
	}

	//随机码集
	var chars = charArrayOf(
			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
			'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
			'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
			'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
	)
		set(value) {
			if (value.isEmpty()) {
				throw IllegalArgumentException("chars cannot be empty!!!")
			}
			field = value
		}

	/**
	 * 记录下一个要绘制的字符的左边距
	 */
	private var paddingLeft: Int = 0

	/**
	 * 记录下一个要绘制的字符的上边距
	 */
	private var paddingTop: Int = 0

	/**
	 * 记录生成的验证码
	 */
	private val builder = StringBuilder()

	private lateinit var code: String

	private var bitmap: Bitmap? = null
	
	init {
		code = createCode()
	}

	//生成验证码图片
	fun createBitmap(): Bitmap {
		// 每次生成验证码图片时初始化
		paddingLeft = 0
		paddingTop = 0

		// 创建画布
		val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
		val canvas = Canvas(bitmap)

		// 绘制背景色
		canvas.drawARGB(0, 0, 0, 0)
		canvas.drawColor(backgroundColor)

		// 初始化画笔
		val paint = Paint()
		paint.textSize = fontSize

		// 遍历验证码，挨个绘制
		for (element in code) {
			randomTextStyle(paint)
			randomPadding()
			canvas.drawText(element.toString() + "", paddingLeft.toFloat(), paddingTop.toFloat(), paint)
		}

		// 绘制干扰线
		for (i in 0 until lineNumber) {
			drawLine(canvas, paint)
		}

		// 保存画布
		canvas.save()
		canvas.restore()
		return bitmap
	}

	/**
	 * 生成随机的验证码
	 */
	fun randomCode(): String {
		code = createCode()
		return code
	}

	/**
	 * 得到图片中的验证码字符串
	 */
	fun getCode(): String {
		return code
	}

	/**
	 * 生成验证码
	 */
	private fun createCode(): String {
		builder.delete(0, builder.length) //使用之前首先清空内容
		for (i in 0 until codeLength) {
			builder.append(chars[random.nextInt(chars.size)])
		}
		return builder.toString()
	}

	/**
	 * 生成干扰线
	 */
	private fun drawLine(canvas: Canvas, paint: Paint) {
		val color = randomColor()
		val startX = random.nextInt(width)
		val startY = random.nextInt(height)
		val stopX = random.nextInt(width)
		val stopY = random.nextInt(height)
		paint.strokeWidth = 1f
		paint.color = color
		canvas.drawLine(startX.toFloat(), startY.toFloat(), stopX.toFloat(), stopY.toFloat(), paint)
	}

	/**
	 * 随机文本样式
	 */
	private fun randomTextStyle(paint: Paint) {
		val color = randomColor()
		paint.color = color
		paint.isFakeBoldText = random.nextBoolean()  //true为粗体，false为非粗体
		var skewX = baseTextSkewX + random.nextFloat() * rangeTextSkewX
		skewX = if (random.nextBoolean()) skewX else -skewX
		paint.textSkewX = skewX //float类型参数，负数表示右斜，整数左斜
		paint.isUnderlineText = random.nextBoolean() //true为下划线，false为非下划线
		paint.isStrikeThruText = random.nextBoolean() //true为删除线，false为非删除线
	}

	/**
	 * 随机颜色
	 */
	private fun randomColor(): Int {
		builder.delete(0, builder.length) //使用之前首先清空内容
		var haxString: String
		for (i in 0..2) {
			haxString = Integer.toHexString(random.nextInt(0xEE))
			if (haxString.length == 1) {
				haxString = "0$haxString"
			}
			builder.append(haxString)
		}
		return Color.parseColor("#$builder")
	}

	/**
	 * 随机间距
	 */
	private fun randomPadding() {
		paddingLeft += if (paddingLeft == 0) baseFirstPaddingLeft else basePaddingLeft
		paddingLeft += random.nextInt(rangePaddingLeft)
		paddingTop = if (random.nextBoolean()) {
			basePaddingTop + random.nextInt(rangePaddingTop)
		} else {
			basePaddingTop - random.nextInt(rangePaddingTop)
		}
	}

	class PictureVerificationFactory {

		companion object {
			fun createDefaultPictureVerification(): PictureVerification {
				return PictureVerification()
			}

			fun createPictureVerification(width: Int, height: Int): PictureVerification {
				val widthScale: Float = width * 1.0f / DEFAULT_WIDTH
				val heightScale: Float = height * 1.0f / DEFAULT_HEIGHT
				val fontSize = DEFAULT_FONT_SIZE * widthScale.coerceAtMost(heightScale)
				val basePaddingTop = (height - fontSize) / 3 + fontSize
				val rangePaddingTop = (height - fontSize) / 4
				return PictureVerification(width = width,
						height = height,
						baseFirstPaddingLeft = (FIRST_BASE_PADDING_LEFT * widthScale).toInt(),
						basePaddingLeft = (BASE_PADDING_LEFT * widthScale).toInt(),
						rangePaddingLeft = (RANGE_PADDING_LEFT * widthScale).toInt(),
						basePaddingTop = basePaddingTop.toInt(),
						rangePaddingTop = rangePaddingTop.toInt(),
						fontSize = fontSize)
			}

		}

	}
}